package com.michael.demos.base.reflect.simple;

import java.lang.reflect.Method;

/**
 * 类功能描述:
 * <pre>
 *   反射的简单使用 - DEMO
 * </pre>
 *
 * @author Michael
 * @version 1.0
 * @date 2020/8/5 11:52
 */
@SuppressWarnings("DuplicatedCode")
public class Demo {

    private String desc;

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    public static Integer COUNT = 10000;

    public static void multipleTest() throws Exception {
        // 正常调用
        long flag10 = System.nanoTime();
        Demo demo = new Demo();
        long flag11 = System.nanoTime();

        for (int i = 0; i < COUNT; i++) {
            demo.setDesc("我是正常的" + i);
            demo.getDesc();
        }
        long flag12 = System.nanoTime();

        // 反射调用
        long flag20 = System.nanoTime();
        Class<?> clazz = Class.forName("com.michael.demos.base.reflect.simple.Demo");
        long flag21 = System.nanoTime();

        Method setDesc = clazz.getMethod("setDesc", String.class);
        Method getDesc = clazz.getMethod("getDesc");
        // 无参构造方法
        //clazz.newInstance();
        // 可以调用有参构造方法
        Object instance = clazz.getConstructor().newInstance();

        for (int i = 0; i < COUNT; i++) {
            setDesc.invoke(instance, "我是反射调用的" + i);
            getDesc.invoke(instance);
        }
        long flag22 = System.nanoTime();

        System.out.println();
        System.out.println("正常调用创建实例时间：" + (flag11 - flag10));
        System.out.println("反射调用创建实例时间：" + (flag21 - flag20));
        System.out.println();
        System.out.println("正常调用调用方法时间：" + (flag12 - flag11));
        System.out.println("反射调用调用方法时间：" + (flag22 - flag21));
    }

    public static void simpleTest() throws Exception {

        // 正常调用
        long flag10 = System.nanoTime();
        Demo demo = new Demo();
        long flag11 = System.nanoTime();

        demo.setDesc("我是正常的");
        demo.getDesc();
        long flag12 = System.nanoTime();

        // 反射调用
        long flag20 = System.nanoTime();
        Class<?> clazz = Class.forName("com.michael.demos.base.reflect.simple.Demo");
        long flag21 = System.nanoTime();

        Method setDesc = clazz.getMethod("setDesc", String.class);
        Method getDesc = clazz.getMethod("getDesc");
        Object instance = clazz.getConstructor().newInstance();

        setDesc.invoke(instance, "我是反射调用的");
        getDesc.invoke(instance);
        long flag22 = System.nanoTime();

        System.out.println();
        System.out.println("正常调用创建实例时间：" + (flag11 - flag10));
        System.out.println("反射调用创建实例时间：" + (flag21 - flag20));
        System.out.println();
        System.out.println("正常调用调用方法时间：" + (flag12 - flag11));
        System.out.println("反射调用调用方法时间：" + (flag22 - flag21));

        /**
         *  结论：
         *  1. 正常调用创建实例比反射快
         *  2. 反射调用方法比正常调用快？ 如果存在System.out.print干扰会出现这种情况
         */
    }

    public static void main(String[] args) throws Exception {

        simpleTest();
        multipleTest();
    }
}
